<?php

/**
* Wordpress Blog Api Component
* @author gerhardsletten / gersh.no
* @license MIT
* @version 0.1
*/
vendor('class-IXR', 'utility', 'gersh_constants');
//class WpBlogApiComponent extends Object {
class WpBlogApiComponent extends IXR_Server {

	var $post_controller = null;
	var $post = null;

	function startup(&$controller) {
		$this->post_controller = $controller;
		$this->post =& new Post();
	}
	
	function WpBlogApiComponent($callbacks = false, $data = false) {
        $this->setCapabilities();
        if ($callbacks) {
            $this->callbacks = $callbacks;
        }
        $this->setCallbacks();
        //$this->serve($data);
    }
	
	function xmlrpc() {
		$methods = array(
			// WordPress API
			'wp.getPage'			=> 'this:wp_getPage',
			'wp.getPages'			=> 'this:wp_getPages',
			'wp.newPage'			=> 'this:wp_newPage',
			'wp.deletePage'			=> 'this:wp_deletePage',
			'wp.editPage'			=> 'this:wp_editPage',
			'wp.getPageList'		=> 'this:wp_getPageList',
			'wp.getAuthors'			=> 'this:wp_getAuthors',
			'wp.getCategories'		=> 'this:mw_getCategories',		// Alias
			'wp.newCategory'		=> 'this:wp_newCategory',
			'wp.suggestCategories'	=> 'this:wp_suggestCategories',
			'wp.uploadFile'			=> 'this:mw_newMediaObject',		// Alias
			
			// PingBack
			'pingback.ping' => 'this:pingback_ping',
			'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',

			'demo.sayHello' => 'this:sayHello',
			'demo.addTwoNumbers' => 'this:addTwoNumbers');
		
		$this->IXR_Server($methods);
		$this->serve($data);
	}
	
	function sayHello($args) {
	    return 'Hello!';
	}
	
	function addTwoNumbers($args) {
	    $number1 = $args[0];
	    $number2 = $args[1];
	    return $number1 + $number2;
	}
	//$post =& new Post();
	//$num_posts = $post->findCount(null, 1);
	
	function login_pass_ok($user_login, $user_pass) {
		//$post =& new Post();
		//$num_posts = $post->findCount(null, 1);
		/*
		if (!user_pass_ok($user_login, $user_pass)) {
			$this->error = new IXR_Error(403, __('Bad login/pass combination.'));
			return false;
		}*/
		return true;
	}
		
	

	/**
	 * WordPress XML-RPC API
	 * wp_getPage
	 */
	function wp_getPage($args) {
		escape($args);

		$blog_id	= (int) $args[0];
		$post_id	= (int) $args[1];
		$username	= $args[2];
		$password	= $args[3];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		if( $post = $this->post->findById($post_id) ) {	
			$post_date = new IXR_Date( date( "Ymd\TH:i:s", mysqlToTimeStamp ($post['Post']['date']) ) );
			$page_struct = array(
				"dateCreated"			=> $post_date,
				"userid"				=> $post['User']['id'],
				"page_id"				=> $post['Post']['id'],
				"page_status"			=> $post['Post']['state'],
				"description"			=> shortenHtml($post['Post']['body'], 50),
				"title"					=> $post['Post']['title'],
				"link"					=> 'http://www.gersh.no' . $post['Post']['url'],
				"permaLink"				=> 'http://www.gersh.no' . $post['Post']['url'],
				"categories"			=> $post['Post']['tags'],
				"excerpt"				=> POST_EXCERPT,
				"text_more"				=> $post['Post']['body'],
				"mt_allow_comments"		=> 0,
				"mt_allow_pings"		=> 0,
				"wp_slug"				=> $post['Post']['slug'],
				"wp_password"			=> $post['User']['password'],
				"wp_author"				=> $post['User']['firstname'] . ' ' . $post['User']['lastname'],
				"wp_page_parent_id"		=> null,
				"wp_page_parent_title"	=> null,
				"wp_page_order"			=> 0,
				"wp_author_id"			=> $post['User']['id'],
				"wp_author_display_name"	=> $post['User']['username'],
				"date_created_gmt"		=> $post_date
			);
			return($page_struct);
		} else {
			return new IXR_Error(404, 'Sorry, no such page.');
		}
	}

	/**
	 * WordPress XML-RPC API
 	 * wp_getPages
	 */
	function wp_getPages($args) {
		escape($args);

		$blog_id	= (int) $args[0];
		$username	= $args[1];
		$password	= $args[2];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Lookup info on pages.
		//$pages = get_pages();
		//$num_pages = count($pages);
		
		$posts = $this->post->findAll(null, null, POST_ORDER, POST_LIMIT_BACKEND);	
		//$posts = $this->post->findById($post_id)
		$num_posts = count($posts);	
		// If we have pages, put together their info.
		if($num_posts >= 1) {
			$pages_struct = array();
			foreach($posts as $post) {
				$page = $this->wp_getPage(array($blog_id, $post['Post']['id'], $username, $password));
				$pages_struct[] = $page;
			}
			/*for($i = 0; $i < $num_posts; $i++) {
				//$page = wp_xmlrpc_server::wp_getPage(array($blog_id, $pages[$i]->ID, $username, $password));
				$page = wp_xmlrpc_server::wp_getPage(array($blog_id, $pages[$i]->ID, $username, $password));
				$pages_struct[] = $page;
			}*/

			return($pages_struct);
		}
		// If no pages were found return an error.
		else {
			return(array());
		}
	}

	/**
	 * WordPress XML-RPC API
 	 * wp_newPage
	 */
	function wp_newPage($args) {
		// Items not escaped here will be escaped in newPost.
		$username	= $this->escape($args[1]);
		$password	= $this->escape($args[2]);
		$page		= $args[3];
		$publish	= $args[4];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Set the user context and check if they are allowed
		// to add new pages.
		$user = set_current_user(0, $username);
		if(!current_user_can("publish_pages")) {
			return(new IXR_Error(401, __("Sorry, you can not add new pages.")));
		}

		// Mark this as content for a page.
		$args[3]["post_type"] = "page";

		// Let mw_newPost do all of the heavy lifting.
		return($this->mw_newPost($args));
	}

	/**
	 * WordPress XML-RPC API
	 * wp_deletePage
	 */
	function wp_deletePage($args) {
		$this->escape($args);

		$blog_id	= (int) $args[0];
		$username	= $args[1];
		$password	= $args[2];
		$page_id	= (int) $args[3];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Get the current page based on the page_id and
		// make sure it is a page and not a post.
		$actual_page = wp_get_single_post($page_id, ARRAY_A);
		if(
			!$actual_page
			|| ($actual_page["post_type"] != "page")
		) {
			return(new IXR_Error(404, __("Sorry, no such page.")));
		}

		// Set the user context and make sure they can delete pages.
		set_current_user(0, $username);
		if(!current_user_can("delete_page", $page_id)) {
			return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
		}

		// Attempt to delete the page.
		$result = wp_delete_post($page_id);
		if(!$result) {
			return(new IXR_Error(500, __("Failed to delete the page.")));
		}

		return(true);
	}

	/**
	 * WordPress XML-RPC API
	 * wp_editPage
	 */
	function wp_editPage($args) {
		// Items not escaped here will be escaped in editPost.
		$blog_id	= (int) $args[0];
		$page_id	= (int) $this->escape($args[1]);
		$username	= $this->escape($args[2]);
		$password	= $this->escape($args[3]);
		$content	= $args[4];
		$publish	= $args[5];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Get the page data and make sure it is a page.
		$actual_page = wp_get_single_post($page_id, ARRAY_A);
		if(
			!$actual_page
			|| ($actual_page["post_type"] != "page")
		) {
			return(new IXR_Error(404, __("Sorry, no such page.")));
		}

		// Set the user context and make sure they are allowed to edit pages.
		set_current_user(0, $username);
		if(!current_user_can("edit_page", $page_id)) {
			return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
		}

		// Mark this as content for a page.
		$content["post_type"] = "page";

		// Arrange args in the way mw_editPost understands.
		$args = array(
			$page_id,
			$username,
			$password,
			$content,
			$publish
		);

		// Let mw_editPost do all of the heavy lifting.
		return($this->mw_editPost($args));
	}

	/**
	 * WordPress XML-RPC API
	 * wp_getPageList
	 */
	function wp_getPageList($args) {
		global $wpdb;

		$this->escape($args);

		$blog_id				= (int) $args[0];
		$username				= $args[1];
		$password				= $args[2];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Get list of pages ids and titles
		$page_list = $wpdb->get_results("
			SELECT ID page_id,
				post_title page_title,
				post_parent page_parent_id,
				post_date_gmt,
				post_date
			FROM {$wpdb->posts}
			WHERE post_type = 'page'
			ORDER BY ID
		");

		// The date needs to be formated properly.
		$num_pages = count($page_list);
		for($i = 0; $i < $num_pages; $i++) {
			$post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date);
			$post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt);

			$page_list[$i]->dateCreated = new IXR_Date($post_date);
			$page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);

			unset($page_list[$i]->post_date_gmt);
			unset($page_list[$i]->post_date);
		}

		return($page_list);
	}

	/**
	 * WordPress XML-RPC API
	 * wp_getAuthors
	 */
	function wp_getAuthors($args) {
		global $wpdb;

		$this->escape($args);

		$blog_id	= (int) $args[0];
		$username	= $args[1];
		$password	= $args[2];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		return(get_users_of_blog());
	}

	/**
	 * WordPress XML-RPC API
	 * wp_newCategory
	 */
	function wp_newCategory($args) {
		$this->escape($args);

		$blog_id				= (int) $args[0];
		$username				= $args[1];
		$password				= $args[2];
		$category				= $args[3];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		// Set the user context and make sure they are
		// allowed to add a category.
		set_current_user(0, $username);
		if(!current_user_can("manage_categories", $page_id)) {
			return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
		}

		// If no slug was provided make it empty so that
		// WordPress will generate one.
		if(empty($category["slug"])) {
			$category["slug"] = "";
		}

		// If no parent_id was provided make it empty
		// so that it will be a top level page (no parent).
		if ( !isset($category["parent_id"]) )
			$category["parent_id"] = "";

		// If no description was provided make it empty.
		if(empty($category["description"])) {
			$category["description"] = "";
		}

		$new_category = array(
			"cat_name"				=> $category["name"],
			"category_nicename"		=> $category["slug"],
			"category_parent"		=> $category["parent_id"],
			"category_description"	=> $category["description"]
		);

		$cat_id = wp_insert_category($new_category);
		if(!$cat_id) {
			return(new IXR_Error(500, __("Sorry, the new category failed.")));
		}

		return($cat_id);
	}

	/**
	 * WordPress XML-RPC API
	 * wp_suggestCategories
	 */
	function wp_suggestCategories($args) {
		global $wpdb;

		$this->escape($args);

		$blog_id				= (int) $args[0];
		$username				= $args[1];
		$password				= $args[2];
		$category				= $args[3];
		$max_results			= (int) $args[4];

		if(!$this->login_pass_ok($username, $password)) {
			return($this->error);
		}

		$args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
		$category_suggestions = get_categories($args);

		return($category_suggestions);
	}
	
	/* metaweblog.getCategories ...returns the list of categories on a given blog */
	function mw_getCategories($args) {

		global $wpdb;

		$this->escape($args);

		$blog_ID     = (int) $args[0];
		$user_login  = $args[1];
		$user_pass   = $args[2];

		if (!$this->login_pass_ok($user_login, $user_pass)) {
			return $this->error;
		}

		$categories_struct = array();

		if ( $cats = get_categories('get=all') ) {
			foreach ( $cats as $cat ) {
				$struct['categoryId'] = $cat->term_id;
				$struct['parentId'] = $cat->parent;
				$struct['description'] = $cat->name;
				$struct['categoryName'] = $cat->name;
				$struct['htmlUrl'] = wp_specialchars(get_category_link($cat->term_id));
				$struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat->term_id, $cat->name));

				$categories_struct[] = $struct;
			}
		}

		return $categories_struct;
	}
	
	/* metaweblog.newMediaObject uploads a file, following your settings */
	function mw_newMediaObject($args) {
		// adapted from a patch by Johann Richard
		// http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/

		global $wpdb;

		$blog_ID     = (int) $args[0];
		$user_login  = $wpdb->escape($args[1]);
		$user_pass   = $wpdb->escape($args[2]);
		$data        = $args[3];

		$name = sanitize_file_name( $data['name'] );
		$type = $data['type'];
		$bits = $data['bits'];

		logIO('O', '(MW) Received '.strlen($bits).' bytes');

		if ( !$this->login_pass_ok($user_login, $user_pass) )
			return $this->error;

		set_current_user(0, $user_login);
		if ( !current_user_can('upload_files') ) {
			logIO('O', '(MW) User does not have upload_files capability');
			$this->error = new IXR_Error(401, __('You are not allowed to upload files to this site.'));
			return $this->error;
		}

		if ( $upload_err = apply_filters( "pre_upload_error", false ) )
			return new IXR_Error(500, $upload_err);

		if(!empty($data["overwrite"]) && ($data["overwrite"] == true)) {
			// Get postmeta info on the object.
			$old_file = $wpdb->get_row("
				SELECT ID
				FROM {$wpdb->posts}
				WHERE post_title = '{$name}'
					AND post_type = 'attachment'
			");

			// Delete previous file.
			wp_delete_attachment($old_file->ID);

			// Make sure the new name is different by pre-pending the
			// previous post id.
			$filename = preg_replace("/^wpid\d+-/", "", $name);
			$name = "wpid{$old_file->ID}-{$filename}";
		}

		$upload = wp_upload_bits($name, $type, $bits, $overwrite);
		if ( ! empty($upload['error']) ) {
			$errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
			logIO('O', '(MW) ' . $errorString);
			return new IXR_Error(500, $errorString);
		}
		// Construct the attachment array
		// attach to post_id -1
		$post_id = -1;
		$attachment = array(
			'post_title' => $name,
			'post_content' => '',
			'post_type' => 'attachment',
			'post_parent' => $post_id,
			'post_mime_type' => $type,
			'guid' => $upload[ 'url' ]
		);

		// Save the data
		$id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
		wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );

		return apply_filters( 'wp_handle_upload', array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type ) );
	}

}